package org.gridgain.internal.h2.vector;

import org.gridgain.internal.h2.recur.TailInvoke;
import org.gridgain.internal.h2.recur.TailRecursion;
import org.gridgain.internal.h2.util.DistanceFunctions;
import org.gridgain.internal.h2.vector.tx.MyVersionedValueCommitted;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class MyVectorUtil {

//    public static Set<Object> getResult(MyPage root, MyPage root1, Object key, int range)
//    {
//        if (range > 0) {
//            Object[] p = MyUtil.query(root, key);
//            Object[] p1 = MyUtil.query(root1, key);
//            if (p != null && p1 != null)
//            {
//                MyLeft myLeft = new MyLeft(root, key, (MyPage) p[0], (int) p[1]);
//                MyRight myRight = new MyRight(root, key, (MyPage) p[0], (int) p[1] + 1);
//                MyLeft myLeft1 = new MyLeft(root, key, (MyPage) p1[0], (int) p1[1]);
//                MyRight myRight1 = new MyRight(root, key, (MyPage) p1[0], (int) p1[1] + 1);
//                Set<Object> set = getResult(myLeft, myRight, myLeft1, myRight1, new HashSet<>(), range, new HashSet<>()).invoke();
//                return set;
//            }
//        }
//        return null;
//    }

    public static List<Object> getResult(MyPage root, MyPage root1, Double[] key, int range)
    {
        if (range > 0) {
            Double keyEu = DistanceFunctions.euclideanDistance(MyUtil.getDs(key), key);
            Double keyCos = DistanceFunctions.cosineDistance(MyUtil.getDsCos(key), key);
            Object[] p = MyUtil.query(root, keyEu);
            Object[] p1 = MyUtil.query(root1, keyCos);
            if (p != null && p1 != null)
            {
                MyLeft myLeft = new MyLeft(root, keyEu, (MyPage) p[0], (int) p[1]);
                MyRight myRight = new MyRight(root, keyEu, (MyPage) p[0], (int) p[1] + 1);
                MyLeft myLeft1 = new MyLeft(root, keyCos, (MyPage) p1[0], (int) p1[1]);
                MyRight myRight1 = new MyRight(root, keyCos, (MyPage) p1[0], (int) p1[1] + 1);
                List<Object> lst = getResult(myLeft, myRight, myLeft1, myRight1, new HashSet<>(), range + 1, new ArrayList<>()).invoke();
                //List<Object> lst1 = lst.subList(lst.size() - 2, lst.size());
                return lst;
            }
        }
        return null;
    }

    private static Integer addAll(Set<Object> all, List<Object> rs, Integer range, Set<Object> m)
    {
        if (m != null) {
            for (Object o : m) {
                if (all.contains(o)) {
                    all.remove(o);
                    if (rs.add(o)) {
                        range--;
                    }

                    if (range <= 0) {
                        return range;
                    }
                } else {
                    all.add(o);
                }
            }
        }
        return range;
    }

    private static TailRecursion<List<Object>> getResult(MyLeft myLeft, MyRight myRight, MyLeft myLeft1, MyRight myRight1, Set<Object> all, Integer range, List<Object> rs)
    {
        if ((myLeft != null || myRight != null) && (myLeft1 != null || myRight1 != null))
        {
            int m_left = -1;
            if (myLeft != null)
            {
                m_left = myLeft.getLeft();
            }

            int m_right = -1;
            if (myRight != null)
            {
                m_right = myRight.getRight();
            }

            int m_left1 = -1;
            if (myLeft1 != null)
            {
                m_left1 = myLeft1.getLeft();
            }

            int m_right1 = -1;
            if (myRight1 != null)
            {
                m_right1 = myRight1.getRight();
            }

            if (m_left != -1 && range > 0) {
                MyVersionedValueCommitted mv = (MyVersionedValueCommitted) myLeft.getP().getValue(m_left);
                HashSet<Object> vs = (HashSet<Object>) mv.value;
                range = addAll(all, rs, range, vs);
            }

            if (m_right != -1 && range > 0) {
                MyVersionedValueCommitted mv = (MyVersionedValueCommitted) myRight.getP().getValue(m_right); //MyPage.get(myRight.getP(), m_right);
                HashSet<Object> vs = (HashSet<Object>) mv.value;
                range = addAll(all, rs, range, vs);
            }

            if (m_left1 != -1 && range > 0) {
                MyVersionedValueCommitted mv = (MyVersionedValueCommitted) myLeft1.getP().getValue(m_left1); //MyPage.get(myLeft1.getP(), m_left1);
                HashSet<Object> vs = (HashSet<Object>) mv.value;
                range = addAll(all, rs, range, vs);
            }

            if (m_right1 != -1 && range > 0) {
                MyVersionedValueCommitted mv = (MyVersionedValueCommitted) myRight1.getP().getValue(m_right1); //MyPage.get(myRight1.getP(), m_right1);
                HashSet<Object> vs = (HashSet<Object>) mv.value;
                range = addAll(all, rs, range, vs);
            }

            if (m_left == -1 && m_right == -1 && m_left1 == -1 && m_right1 == -1) {
                return TailInvoke.done(rs);
            }

            if (range > 0) {
                int myRange1 = range;
                return TailInvoke.call(() -> getResult(myLeft, myRight, myLeft1, myRight1, all, myRange1, rs));
            }
        }
        return TailInvoke.done(rs);
    }
}






























